package xyz.eden.cloud.common.core.util;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

public class LocalDatetimeUtils {

    /**
     * 解析
     *
     * @param pattern
     * @param dataStr
     * @return
     */
    public static LocalDateTime parse(String pattern, String dataStr) {
        return parse(pattern, dataStr, ZoneOffset.UTC);
    }

    /**
     * 解析
     *
     * @param pattern
     * @param dataStr
     * @param zoneId
     * @return
     */
    public static LocalDateTime parse(String pattern, String dataStr, ZoneId zoneId) {
        if (StringUtils.isBlank(pattern) || StringUtils.isBlank(dataStr)) {
            return null;
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern).withZone(getZoneId(zoneId));
        return LocalDateTime.parse(dataStr, dateTimeFormatter);
    }

    /**
     * 格式化
     *
     * @param pattern
     * @param localDateTime
     * @return
     */
    public static String formatStr(String pattern, LocalDateTime localDateTime) {
        return formatStr(pattern, localDateTime, ZoneOffset.UTC);
    }

    /**
     * 格式化
     *
     * @param pattern
     * @param localDateTime
     * @param zoneId
     * @return
     */
    public static String formatStr(String pattern, LocalDateTime localDateTime, ZoneId zoneId) {
        if (Objects.isNull(localDateTime) || StringUtils.isBlank(pattern)) {
            return "";
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern).withZone(getZoneId(zoneId));
        return dateTimeFormatter.format(localDateTime);
    }

    /**
     * now UTF LocalDateTime
     *
     * @return
     */
    public static LocalDateTime nowUtc() {
        return LocalDateTime.now(ZoneOffset.UTC);
    }

    /**
     * Date to LocalDateTime
     *
     * @param localDateTime
     * @return
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return toDate(localDateTime, ZoneOffset.UTC);
    }

    /**
     * Date to LocalDateTime
     *
     * @param localDateTime
     * @param zone
     * @return
     */
    public static Date toDate(LocalDateTime localDateTime, ZoneId zone) {
        if (Objects.isNull(localDateTime)) {
            return null;
        }
        return Date.from(localDateTime.atZone(getZoneId(zone)).toInstant());
    }

    /**
     * Date to UTC Zone LocalDateTime
     *
     * @param date
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return toLocalDateTime(date, ZoneOffset.UTC);
    }

    /**
     * Date to LocalDateTime
     * <p> default zoneId is ZoneOffset.UTC</p>
     *
     * @param date
     * @param zone
     * @return
     */
    public static LocalDateTime toLocalDateTime(Date date, ZoneId zone) {
        if (Objects.isNull(date)) {
            return null;
        }
        return date.toInstant().atZone(getZoneId(zone)).toLocalDateTime();
    }

    /**
     * LocalDateTime to timestamp
     *
     * @param localDateTime
     * @return
     */
    public static Long toTimestamp(LocalDateTime localDateTime) {
        return localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
    }

    /**
     * LocalDateTime to timestamp
     *
     * @param localDateTime
     * @return
     */
    public static Long toTimestamp(LocalDateTime localDateTime, ZoneOffset zoneOffset) {
        if (Objects.isNull(localDateTime)) {
            return null;
        }
        return localDateTime.toInstant(getZoneOffset(zoneOffset)).toEpochMilli();
    }

    /**
     * timestamp to UTC Zone LocalDateTime
     *
     * @param timestamp
     * @return
     */
    public static LocalDateTime toLocalDateTime(Long timestamp) {
        return LocalDatetimeUtils.toLocalDateTime(timestamp, ZoneOffset.UTC);
    }

    /**
     * timestamp to UTC Zone LocalDateTime
     *
     * @param timestamp
     * @return
     */
    public static LocalDateTime toLocalDateTime(Long timestamp, ZoneId zone) {
        if (Objects.isNull(timestamp)) {
            return null;
        }
        return Instant.ofEpochMilli(timestamp).atZone(getZoneId(zone)).toLocalDateTime();
    }

    private static ZoneOffset getZoneOffset(ZoneOffset zoneOffset) {
        return Objects.isNull(zoneOffset) ? ZoneOffset.UTC : zoneOffset;
    }

    private static ZoneId getZoneId(ZoneId zone) {
        return Objects.isNull(zone) ? ZoneOffset.UTC : zone;
    }
}
